#include <libusb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>

#define ID_VENDOR 0x1294
#define ID_PRODUCT 0x1320

libusb_device_handle * handle;

void setcolour(char* colour) {
	int error, transfered;
	error = libusb_interrupt_transfer(handle, 0x02, colour, sizeof(char), &transfered, 100);
	if (error) {
		printf("error; %d\n", error);
	}
}

int main(int argc, char * argv[]) {

	bool loop = false;
	bool pwm = false;
	int count = 0;
	int delay = 0;
	char colours[256];
	int numcolours = 0;

	int cycle = 0;
	char off = 0;

	if (argc != 2 && argc != 3 && argc < 5) {
		printf("Set colour and exit\n");
		printf("%s <colour>\n", argv[0]);
		printf("Crappy PWM mode -- affected by other work on the machine, freq does nothing ATM\n");
		printf("%s <colour> <frenquency>\n", argv[0]);
		printf("Cycle colours <cycle count> times with delay of <toggle delay>. Cycle count of 0 means repeat until killed.\n");		
		printf("%s <cycle count> <toggle delay> <colour 1> <color 2> ... <color 256>\n", argv[0]);
		printf("--- Colours ---\n");
		printf("0 - off\n");
		printf("1 - Blue\n");
		printf("2 - Red\n");
		printf("3 - Green\n");
		printf("4 - Aqua\n");
		printf("5 - Purple\n");
		printf("6 - Yellow\n");
		printf("7 - White\n");
		return 1;
	}

	if (argc == 2 || argc == 3) {
		colours[0] = (char) atoi(argv[1]);
		if(argc == 3){
			pwm = true;
		}
	}

	else if (argc >= 5) {
		loop = true;
		count = atoi(argv[1]);
		delay = atoi(argv[2]) * 1000;

		for (int i = 3; i < argc && numcolours < 256; i++) {
			char colour = (char) atoi(argv[i]);
			colours[i - 3] = colour;
			numcolours++;
		}
	}

	libusb_init(NULL);

	handle = libusb_open_device_with_vid_pid(NULL, ID_VENDOR, ID_PRODUCT);

	if (handle == NULL) {
		printf("Device not found\n");
		libusb_exit(NULL);
		return 1;
	}

	if (libusb_kernel_driver_active(handle, 0)) {
		libusb_detach_kernel_driver(handle, 0);
	}

	if (libusb_claim_interface(handle, 0) < 0) {
		printf("Interface error\n");
		libusb_exit(NULL);
		return 1;
	}

	// Looping sequence mode
	if (loop) {
		int current = 0;
		while (true) {
			setcolour(&colours[current]);
			usleep(delay);
			current++;

			if (current == numcolours && count > 0) {
				cycle++;
				if (cycle == count) {
					break;
				}
			}

			if (current == numcolours) {
				current = 0;
			}
		}

		usleep(delay);
		setcolour(&off);
	}

	if(pwm){
		int period = 15000;
		int duty = 0;
		int step = 50;

		while(true){
			setcolour(&colours[0]);
			usleep(duty);
			setcolour(&off);
			usleep(period - duty);

			duty += step;

			if(duty < 0){
				step = -step;
				duty = 0;
			}
			else if(duty > period){
				step = -step;
				duty = period;

			}

		}

	}

	// Set and exit mode
	else {
		setcolour(&colours[0]);
	}

	libusb_attach_kernel_driver(handle, 0);
	libusb_close(handle);
	libusb_exit(NULL);

	return 0;

}

